/**
 * 
 */
package com.oauth.linkedin.server.service;

import java.util.EnumSet;
import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;

import com.google.code.linkedinapi.client.LinkedInApiClient;
import com.google.code.linkedinapi.client.LinkedInApiClientFactory;
import com.google.code.linkedinapi.client.enumeration.ProfileField;
import com.google.code.linkedinapi.client.oauth.LinkedInAccessToken;
import com.google.code.linkedinapi.client.oauth.LinkedInOAuthService;
import com.google.code.linkedinapi.client.oauth.LinkedInOAuthServiceFactory;
import com.google.code.linkedinapi.client.oauth.LinkedInRequestToken;
import com.google.code.linkedinapi.schema.Connections;
import com.google.code.linkedinapi.schema.Network;
import com.google.code.linkedinapi.schema.Person;
import com.oauth.common.server.beans.OAuthAccessToken;
import com.oauth.common.server.beans.OAuthConfigBean;
import com.oauth.common.server.beans.OAuthRequestToken;
import com.oauth.linkedin.client.beans.LinkedinUser;
import com.oauth.linkedin.server.beans.LinkedinBean;
import com.oauth.linkedin.server.beans.LinkedinRequestToken;
import com.oauth.linkedin.server.util.LinkedinUtil;
import com.oauth.service.application.global.beans.Birthday;
import com.oauth.service.generic.OAuthService;
import com.oauth.service.generic.beans.OAuthServiceBean;

/**
 * @author asanthan
 * 
 */
public class LinkedinServiceImpl implements LinkedinService {

	private LinkedInOAuthService linkedInOauthService;
	private LinkedInApiClientFactory factory;

	private OAuthService mOAuthService;
	private OAuthConfigBean mOAuthConfigBean;

	/**
	 * @param pOAuthService
	 *            the oAuthService to set
	 */
	@Autowired(required = true)
	public void setOAuthService(OAuthService pOAuthService) {
		mOAuthService = pOAuthService;
	}

	/**
	 * @param pOAuthConfigBean
	 *            the oAuthConfigBean to set
	 */
	@Required
	public void setOAuthConfigBean(OAuthConfigBean pOAuthConfigBean) {
		mOAuthConfigBean = pOAuthConfigBean;
	}

	@PostConstruct
	public void initialize() {
		linkedInOauthService = LinkedInOAuthServiceFactory.getInstance()
				.createLinkedInOAuthService(mOAuthConfigBean.getConsumerKey(),
						mOAuthConfigBean.getConsumerSecret());
		factory = LinkedInApiClientFactory.newInstance(mOAuthConfigBean.getConsumerKey(),
				mOAuthConfigBean.getConsumerSecret());
	}

	private LinkedInApiClient getLinkedInClient(Long pMemberId) throws Exception {
		OAuthAccessToken accessToken = getAccessTokenFromDB(pMemberId);
		LinkedInAccessToken linkedinToken = new LinkedInAccessToken(accessToken.getToken(),
				accessToken.getTokenSecret());
		LinkedInApiClient client = factory.createLinkedInApiClient(linkedinToken);
		return client;
	}

	private Person getProfile(Long pMemberId, EnumSet<ProfileField> pFieldSet) throws Exception {
		return getLinkedInClient(pMemberId).getProfileForCurrentUser(pFieldSet);
	}

	@Override
	public OAuthAccessToken getAccessTokenFromDB(Long pMemberId) throws Exception {
		OAuthServiceBean token = null;
		token = mOAuthService.getToken(pMemberId, LinkedinBean.class);
		if (token != null) {
			return new OAuthAccessToken(token.getAccessToken(), token.getAccessTokenSecret());
		}
		return null;
	}

	@Override
	public OAuthAccessToken getAccessTokenFromRequestToken(OAuthRequestToken pRequestToken,
			String pVerifier) throws Exception {
		LinkedInRequestToken requestToken = new LinkedInRequestToken(pRequestToken.getToken(),
				pRequestToken.getTokenSecret());
		LinkedInAccessToken accessToken = linkedInOauthService.getOAuthAccessToken(requestToken,
				pVerifier);

		// Get access token .
		return new OAuthAccessToken(accessToken.getToken(), accessToken.getTokenSecret());
	}

	@Override
	public LinkedinRequestToken getRequestToken() throws Exception {
		LinkedInRequestToken requestToken = linkedInOauthService
				.getOAuthRequestToken(mOAuthConfigBean.getCallBackUrl());
		return new LinkedinRequestToken(requestToken.getToken(), requestToken.getTokenSecret(),
				requestToken.getAuthorizationUrl());
	}

	@Override
	public void persistAccessToken(OAuthAccessToken pAccessToken, Long pMemberId) throws Exception {
		LinkedinBean serviceBean = new LinkedinBean();
		serviceBean.setAccessToken(pAccessToken.getToken());
		serviceBean.setAccessTokenSecret(pAccessToken.getTokenSecret());
		serviceBean.setMemberId(pMemberId);
		// serviceBean.setTwitterId(twitter.getUserId());
		mOAuthService.persistToken(serviceBean); // persist in db for future
		// use.
	}

	@Override
	public List<LinkedinUser> getConnections(Long pMemberId) throws Exception {
		Connections connections = getLinkedInClient(pMemberId).getConnectionsForCurrentUser();
		return LinkedinUtil.getUsers(connections);
	}

	@Override
	public List<Birthday> getUpcomingBirthdays(Long pMemberId, int pBirthdayInterval)
			throws Exception {
		Connections connections = getLinkedInClient(pMemberId).getConnectionsForCurrentUser(
				EnumSet.of(ProfileField.DATE_OF_BIRTH, ProfileField.FIRST_NAME,
						ProfileField.LAST_NAME, ProfileField.ID, ProfileField.PICTURE_URL,
						ProfileField.PUBLIC_PROFILE_URL));
		return LinkedinUtil.getBirthdays(connections, pBirthdayInterval);

	}

	@Override
	public List<LinkedinUser> getMessages(Long pMemberId) throws Exception {
		// getLinkedInClient(pMemberId).getp
		return null;
	}

	@Override
	public List<LinkedinUser> getUpdates(Long pMemberId) throws Exception {
		Network network = getLinkedInClient(pMemberId).getNetworkUpdates(LinkedinUtil.updatesSet);
		return LinkedinUtil.getUpdates(network.getUpdates());

	}

	@Override
	public LinkedinUser getLinkedinUser(Long pMemberId) throws Exception {
		Person profile = getProfile(pMemberId, EnumSet.of(ProfileField.FIRST_NAME,
				ProfileField.LAST_NAME, ProfileField.HEADLINE, ProfileField.PICTURE_URL,
				ProfileField.CURRENT_STATUS));
		return LinkedinUtil.getUser(profile);
	}

	@Override
	public void updateStatus(String pText, Long pMemberId) throws Exception {
		System.out.println("Updating..." + pText);
		getLinkedInClient(pMemberId).postNetworkUpdate(pText);
	}
}
